/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ania2.engine;

import ania2.BoardPosition;

/**
 *
 * @author pawel
 */
public class AdvancedPositionEstimator implements PositionEstimator {

    private static final int PIECE_VALUE = 100;
    private static final int QUEEN_VALUE = 250;
    private static final int FLANK_INBALANCE_PUNISHMENT = 2;
    private static final int PIECE_IN_CENTRE = 5;
    private static final int PIECE_IN_FIRST_LINE=2;
    private static final int LAGGING_PIECE_PUNISHMENT = 5;
    private static final int RIGHT_FLANK_TIED_WITHOUT_G1_PUNISHMENT = 50;
    private static final int RIGHT_FLANK_TIED_WITH_G1_PUNISHMENT = 20;
    private static final long CENTRE_MASK;
    private static final long[] LINES;
    private static final long TIED1_WHITE;
    private static final long TIED1_BLACK;
    private static final long B8;
    private static final long TIED2_WHITE;
    private static final long TIED2_BLACK;
    private static final long G1;
    
    static {
        CENTRE_MASK = (1L<<48) + (1L<<47) + (1L<<43) + (1L<<42) + (1L<<39) + (1L<<38) + (1L<<34) + (1L<<33);
        LINES = new long[8];
        LINES[0] = (1L<<58) + (1L<<57) + (1L<<56) + (1L<<55);
        LINES[1] = (1L<<53) + (1L<<52) + (1L<<51) + (1L<<50);
        LINES[2] = (1L<<49) + (1L<<48) + (1L<<47) + (1L<<46);
        LINES[3] = (1L<<44) + (1L<<43) + (1L<<42) + (1L<<41);
        LINES[4] = (1L<<40) + (1L<<39) + (1L<<38) + (1L<<37);
        LINES[5] = (1L<<35) + (1L<<34) + (1L<<33) + (1L<<32);
        LINES[6] = (1L<<31) + (1L<<30) + (1L<<29) + (1L<<28);
        LINES[7] = (1L<<26) + (1L<<25) + (1L<<24) + (1L<<23);
        TIED1_WHITE = (1L<<40) + (1L<<44) + (1L<<49);
        TIED1_BLACK = (1L<<39) + (1L<<35) + (1L<<34) + (1L<<30);
        B8 = (1L<<26);
        TIED2_WHITE = (1L<<42) + (1L<<47) + (1L<<46) + (1L<<51);
        TIED2_BLACK = (1L<<32) + (1L<<37) + (1L<<41);
        G1 = (1L<<55);
    }
    
    public int estimatePosition(BoardPosition position, boolean whiteTurn) {
        long allWhite = position.getWhitePieces();
        long allBlack = position.getBlackPieces();
        long queens = position.getQueens();
        int value = 0;
        long whitePieces = allWhite & ~queens;
        long blackPieces = allBlack & ~queens;
        long whiteQueens = allWhite & queens;
        long blackQueens = allBlack & queens;
        int whitePiecesCardinality= getCardinality(whitePieces);
        int blackPiecesCardinality= getCardinality(blackPieces);
        int whiteQueensCardinality= getCardinality(whiteQueens);
        int blackQueensCardinality= getCardinality(blackQueens);
        value += (whitePiecesCardinality-blackPiecesCardinality)*PIECE_VALUE +
                (whiteQueensCardinality-blackQueensCardinality)*QUEEN_VALUE;
        GamePhase phase = getGamePhase(whitePiecesCardinality, blackPiecesCardinality);
        int tempoBalance = getTempoBalance(whitePieces, blackPieces);
        switch(phase) {
            case OPENING: value-=2*tempoBalance; break;
            case MIDGAME: break;
            case ENDGAME: value+=2*tempoBalance;
        }
        value += getCentreBalance(whitePieces, blackPieces);
        //value += getRightBlacksFlankTied(whitePieces, blackPieces);
        //value += getRightWhitesFlankTied(whitePieces, blackPieces);
        return (whiteTurn)? value : -value;
    }
    
    
    private int getCentreBalance(long whitePieces, long blackPieces) {
        
        long whiteInCentre = whitePieces & CENTRE_MASK;
        long blackInCentre = blackPieces & CENTRE_MASK;
        int centre = getCardinality(whiteInCentre);
        centre -= getCardinality(blackInCentre);
        return centre *PIECE_IN_CENTRE;
    }
    
    private int getTempoBalance(long whitePieces, long blackPieces) {
        int balance= 0;
        for(int i=0; i<8; i++) {
            balance+= (getCardinality(whitePieces&LINES[i])-getCardinality(blackPieces&LINES[7-i]))*(i+1);
        }
        return balance;
    }
    
    private int getRightBlacksFlankTied(long whitePieces, long blackPieces) {
        if((whitePieces & TIED1_WHITE) == TIED1_WHITE && (blackPieces & TIED1_BLACK)==TIED1_BLACK) {
            if((blackPieces & B8)==B8)
                return RIGHT_FLANK_TIED_WITH_G1_PUNISHMENT;
            else
                return RIGHT_FLANK_TIED_WITHOUT_G1_PUNISHMENT;
        }
        return 0;
    }
    
    private int getRightWhitesFlankTied(long whitePieces, long blackPieces) {
        if((whitePieces & TIED2_WHITE) == TIED2_WHITE && (blackPieces & TIED2_BLACK)==TIED2_BLACK) {
            if((whitePieces & G1)==G1)
                return -RIGHT_FLANK_TIED_WITH_G1_PUNISHMENT;
            else
                return -RIGHT_FLANK_TIED_WITHOUT_G1_PUNISHMENT;
        }
        return 0;
    }
    
    private int getCardinality(long bitBoard) {
        int cardinality = 0;
        long bit = Long.highestOneBit(bitBoard);
        while(bit != 0) {
            bitBoard ^= bit;
            cardinality++;
            bit = Long.highestOneBit(bitBoard);
        }
        return cardinality;
    }
    
    private GamePhase getGamePhase(int whitePiecesCardinality, int blackPiecesCardinality) {
        int cardinality = whitePiecesCardinality+blackPiecesCardinality;
        if( cardinality >= 18 )
            return GamePhase.OPENING;
        else if(cardinality <= 10)
            return GamePhase.ENDGAME;
        else 
            return GamePhase.MIDGAME;
    }
    
    private enum GamePhase {OPENING, MIDGAME, ENDGAME };

    
}
